package com.spzx.product.service.impl;

/**
 * @Author GQS @Date 2024/9/20/14:36 @Description
 */
import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.spzx.product.api.domain.vo.CategoryVo;
import com.spzx.product.domain.Category;
import com.spzx.product.domain.CategoryBrand;
import com.spzx.product.domain.vo.CategoryExcelVo;
import com.spzx.product.helper.CategoryHelper;
import com.spzx.product.mapper.CategoryMapper;
import com.spzx.product.service.CategoryService;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/** 商品分类Service业务层处理 */
@Service
public class CategoryServiceImpl extends ServiceImpl<CategoryMapper, Category>
    implements CategoryService {

  @Autowired private CategoryMapper categoryMapper;

  @Override
  public List<Category> treeSelect(Long parentId) {
    // 根据父类ID查询子类列表
    List<Category> categoryList =
        categoryMapper.selectList(
            new LambdaQueryWrapper<Category>().eq(Category::getParentId, parentId));
    // 如果查询到子类列表且不为空
    if (!CollectionUtils.isEmpty(categoryList)) {
      // 遍历子类列表
      categoryList.forEach(
          item -> {
            // 统计当前子类的子类数量
            long count =
                categoryMapper.selectCount(
                    Wrappers.lambdaQuery(Category.class).eq(Category::getParentId, item.getId()));
            // 如果子类数量大于0，则设置hasChildren为true，表示有子类
            if (count > 0) {
              item.setHasChildren(true);
            } else {
              // 否则设置hasChildren为false，表示没有子类
              item.setHasChildren(false);
            }
          });
    }
    // 返回子类列表
    return categoryList;
  }

  /**
   * 获取指定分类ID的所有父分类ID列表 该方法首先初始化一个空的ArrayList用于存储分类对象， 然后调用 getParentCategoryById
   * 方法根据给定的分类ID获取所有父分类对象， 最终将这些父分类对象的ID提取并反转顺序后返回
   *
   * @param id 三级分类的ID
   * @return 包含自身和所有父分类ID的列表
   */
  @Override
  public List<Long> getAllCategoryIdList(Long id) {
    // 创建一个空的ArrayList用于存储各级分类Id
    List<Long> categoryIds = new ArrayList<>();
    // 递归调用方法 查询上一级Id
    // while (id > 0) {
    //   Category category = this.getById(id);
    //   categoryIds.add(category.getId());
    //   id = category.getParentId();
    // }
    while (id > 0) {
      categoryIds.add(id);
      id = this.getById(id).getParentId();
    }
    Collections.reverse(categoryIds);
    return categoryIds;

    // 创建一个空的ArrayList用于存储分类对象
    // List<Category> categoryList = new ArrayList<>();
    // 根据三级分类id 返回所有父类id
    // List<Category> list = getParentCategoryById(id, categoryList);
    // List<Long> categoryIdList = new ArrayList<>(list.stream().map(Category::getId).toList());
    // 反转列表顺序以获取从高到低的父分类ID顺序
    // Collections.reverse(categoryIdList);

    // return categoryIdList;
  }

  @Override
  public void exportData(HttpServletResponse response) {

    try {
      // 设置响应结果类型
      response.setContentType("application/vnd.ms-excel");
      response.setCharacterEncoding("utf-8");

      // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
      String fileName = URLEncoder.encode("分类数据", "UTF-8");
      response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
      response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");

      // 查询数据库中的数据
      List<Category> categoryList = categoryMapper.selectList(null);
      List<CategoryExcelVo> categoryExcelVoList = new ArrayList<>(categoryList.size());

      // 将从数据库中查询到的Category对象转换成CategoryExcelVo对象
      for (Category category : categoryList) {
        CategoryExcelVo categoryExcelVo = new CategoryExcelVo();
        BeanUtils.copyProperties(category, categoryExcelVo, CategoryExcelVo.class);
        categoryExcelVoList.add(categoryExcelVo);
      }

      // 写出数据到浏览器端
      EasyExcel.write(response.getOutputStream(), CategoryExcelVo.class)
          .sheet("分类数据")
          .doWrite(categoryExcelVoList);

    } catch (IOException e) {
      e.printStackTrace();
    }
  }

  @Override
  /**
   * 导入分类数据
   *
   * @param file 用户上传的Excel文件 该方法使用EasyExcel库从上传的文件中读取并解析分类数据， 然后将解析后的数据保存到数据库中。
   */
  @Transactional
  public void importData(MultipartFile file) {
    // 使用EasyExcel解析数据
    try {
      // 从上传的Excel文件中读取数据，并将其映射到CategoryExcelVo类对象的列表中
      List<CategoryExcelVo> categoryExcelVoList =
          EasyExcel.read(file.getInputStream()).head(CategoryExcelVo.class).sheet().doReadSync();
      // 检查读取的数据列表是否为空
      if (!CollectionUtils.isEmpty(categoryExcelVoList)) {
        // 初始化一个Category对象的列表，用于存储转换后的数据
        List<Category> categoryList = new ArrayList<>(categoryExcelVoList.size());
        // 遍历Excel数据列表，将每个Excel数据对象转换为Category对象
        for (CategoryExcelVo categoryExcelVo : categoryExcelVoList) {
          Category category = new Category();
          // 将Excel中的数据复制到Category对象
          BeanUtils.copyProperties(categoryExcelVo, category, Category.class);
          // 将转换后的Category对象添加到列表中
          categoryList.add(category);
        }
        // 批量保存分类数据
        this.saveBatch(categoryList);
      }
    } catch (IOException e) {
      // 捕获并转发IOException为RuntimeException
      throw new RuntimeException(e);
    }
  }

    /**
     * 获取一级分类信息
     *
     * 通过查询数据库中所有父ID为0的分类，来获取一级分类列表，并将这些分类转换为CategoryVo对象列表
     *
     * @return 返回一级CategoryVo列表
     */
    @Override
    public List<CategoryVo> getOneCategory() {
      // 从数据库中查询所有一级分类（parentId为0）
      List<Category> topCategoryList = categoryMapper.selectList(Wrappers.lambdaQuery(Category.class).eq(Category::getParentId, 0));

      // 将一级分类列表转换为CategoryVo对象列表
      List<CategoryVo> categoryVoList = topCategoryList.stream().map(category -> {
        CategoryVo categoryVo = new CategoryVo();
        // 复制Category对象的属性到CategoryVo对象
        BeanUtils.copyProperties(category, categoryVo);
        return categoryVo;
      }).toList();

      // 返回转换后的CategoryVo列表
      return categoryVoList;
    }

  @Override
  /**
   * 构建并返回分类树
   *
   * 本方法首先从数据库中获取所有分类信息，然后将其转换为分类的语音对象列表（CategoryVo），
   * 最后调用辅助类CategoryHelper的buildTree方法，将平面的分类列表组装成树状结构
   *
   * @return 返回组装好的分类树，以List形式表示
   */
  public List<CategoryVo> tree() {
    // List<Category> fatherCategoryList = categoryMapper.selectList(Wrappers.lambdaQuery(Category.class).eq(Category::getParentId, 0));
    //
    // List<CategoryVo> fatherCategoryVoList = fatherCategoryList.stream().map(category -> {
    //   CategoryVo categoryVo = new CategoryVo();
    //   BeanUtils.copyProperties(category, categoryVo);
    //   return categoryVo;
    // }).toList();
    // return CategoryHelper.buildTreeCategory(fatherCategoryVoList);


    // 从数据库中获取所有分类信息
    List<Category> allCategoryList = categoryMapper.selectList(null);

    // 将Category实体列表转换为CategoryVo列表
    List<CategoryVo> categoryVoList = allCategoryList.stream().map(item -> {
      CategoryVo categoryVo = new CategoryVo();
      // 使用BeanUtils工具类将Category实体的属性复制到CategoryVo对象中
      BeanUtils.copyProperties(item, categoryVo);
      return categoryVo;
    }).collect(Collectors.toList());

    // 调用辅助类方法，将分类列表组装成树状结构并返回
    return CategoryHelper.buildTree(categoryVoList);



  }




  /**
   * 递归获取给定ID的分类对象及其所有父分类对象 该方法通过调用自身递归地获取分类对象及其父分类对象，
   * 直到根分类（parentId为0）为止将获取的所有分类对象存储在传入的categoryList中并返回
   *
   * @param id 分类的ID
   * @param categoryList 存储分类对象的列表
   * @return 包含给定ID的分类对象及其所有父分类对象的列表
   */
  private List<Category> getParentCategoryById(Long id, List<Category> categoryList) {
    while (id > 0) {
      // 写法一
      // Category category = this.getById(id);
      // Long parentId = category.getParentId();
      // categoryList.add(category);
      // return getParentCategoryById(parentId, categoryList);

      // 写法二
      // 根据给定的ID查询Category对象
      // 此处使用了LambdaQueryWrapper来构建查询条件，仅选择必要的字段以优化查询性能
      Category category =
          categoryMapper.selectOne(
              Wrappers.lambdaQuery(Category.class)
                  .eq(Category::getId, id) // 依据ID字段进行精确查询
                  .select(Category::getId, Category::getParentId)); // 仅选择Id和ParentId字段

      categoryList.add(category);
      return getParentCategoryById(category.getParentId(), categoryList);
    }
    return categoryList;
  }
}
